<?php
namespace Views;
/**
 * File holds class for generating businesses views
 *
 * PHP version 5.3.5
 *
 * @category   CM
 * @package    Views
 * @subpackage -
 * @author     markus karileet <markuskarileet@hotmail.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
 * @link       -
 */
class Business extends Page {
    /**
     * Variable for service object
     * @var \Services\Business
     */
	private $_service;
	
	/**
	 * Constructor initiates super setUp method and appropriate service class
	 */
	public function __construct() {
		$this->setUp();
		$this->_service = new \Services\Business();
	}
	
	/**
	 * Method shows top businesses. Businesses are ordered by Net Promoter score
	 * Upon DB exception, pagePanic is shown
	 * @param int $type Type ID
	 */
	public function viewTop($type = 0) {
	    try {
    		$topLogoCode = "no";
    		
    		//read category businesses
    		$object = new \Entities\Business();
    		$object->setType($type);
    		$businesses = $this->_service->selectMulti($object);
    		
    		//get NPS scores (all time)
    		$npsArray = $this->_service->getNpsScores($businesses);
    		//if some scores were calculated, get top companys code for logo img
    		if (count($npsArray) > 0) {
    			$npsClone = array_keys($npsArray);
    			$topLogoCode = $businesses[array_shift($npsClone)]->getCode();			
    		}
    		
    		//read type name for page title
    		$object = new \Entities\Type();
    		$object->setId($type);
    		$typeService = new \Services\Type();
    		$typeObj = $typeService->select($object);
    
    		//assign template variables
    		$this->_smarty->assign('type', $typeObj->getName());
    		$this->_smarty->assign('businessArray', $businesses);
    		$this->_smarty->assign('topBusinessCode', $topLogoCode);
    		$this->_smarty->assign('npsArray', $npsArray);
    		
    		$this->displayStatic('topBusinesses.tpl');
	    } catch (\Exception $e) {
	        //service threw exception, probably db, so panic
	        $this->_pagePanic();
	    }
	}
	
	/**
	 * Method shows business details page. Db excpetion leads to page panic
	 * @param int $id Business ID
	 */
	public function viewDetails($id) {
	    try {
    		$object = new \Entities\Business();
    		$object->setId($id);
    		$business = $this->_service->select($object);
    		//read nps for business
    		$nps = $this->_service->getNpsScores(array($business));
    		//read feedbacks
    		$feedback = new \Entities\Feedback();
    		$feedback->setBusiness($id);
    		$feedbacks = $this->_service->selectMulti($feedback, 'time', \Enum\Order::Desc);
    		//since getNpsScores returns an array, we only need 1 element, since
    		//1 business is in "comparisson"
    		$this->_smarty->assign('nps', $nps[0]);
    		$this->_smarty->assign('business', $business);
    		$this->_smarty->assign('feedbacks', $feedbacks);
    		
    		$this->displayStatic('companyDetails.tpl');
	    } catch (\Exception $e) {
	        $this->_pagePanic();
	    }
	}
	
	/**
	 * Method shows company editing page when user is logged in
	 * @param int $id Business ID For editing
	 */
	public function viewEditForm($id) {
		if ($this->_loggedInUser && in_array($id, $this->_manageableCompanies)) {
		    try {
    			$object = new \Entities\Business();
    			$object->setId($id);
    			$business = $this->_service->select($object);
    			$this->_smarty->assign('business', $business);
    			if ($this->_loggedInUser->getNotification() != \Enum\Notification::No) {
    			    $this->_smarty->assign('notify', \Enum\Notification::Email);
    			}
    			$account = new \Entities\Account();
    			$accounts = $this->_service->selectMulti($account);
    			$acs = array();
    			//add not connected option
    			$acs[0] = '-';
    			foreach(array_keys($accounts) as $key) {
    				$acs[$accounts[$key]->getId()] = $accounts[$key]->getName(); 
    			}
    			$this->_smarty->assign('accounts', $acs);
    			$this->displayStatic('companyEdit.tpl');
		    } catch (\Exception $e) {
		        $this->_pagePanic();
		    }
		} else {
			$this->_toLoginPage();
		}
	}
	
	/**
	 * Method updates company details. Called via form post
	 * @param array $post HTTP POST array
	 */
	public function update($post) {
		$this->_uploadImage($_FILES, $post['code']);
		if ($this->_loggedInUser && in_array((int)$post['business'], $this->_manageableCompanies)) {
		    try {
    			if ($this->_service->prepareUpdate($post, $this->_loggedInUser) > 0) {
    				$message = array('success' => $this->_translation['editSuccess']);
    			} else {
    				$message = array('error' => $this->_translation['editFail']);
    			}
		    } catch (\Exception $e) {
		        $message = array('error' => $this->_translation['internalError']);
		    }
			$this->setMessage($message);
			$this->viewDetails((int)$post['business']);
		} else {
			$this->_toLoginPage();
		}
	}
	
	private function _uploadImage($file, $code) {
		//check whether user uploaded a image or not
		if (strlen($file["logo"]["name"]) > 0) {
			//check if uploaded file is PNG
			if ($file["logo"]["type"] != "image/png") {
				throw new \Exception('Image can be PNG only!');
			}
			move_uploaded_file($file["logo"]["tmp_name"], APPPATH . 'lib/design/img/logo_'.$code.'.png');
		}
		
	}
	
	/**
	 * Method shows my company comments and scores page
	 * @param int $id Business ID for comments and scores
	 */
	public function viewMyScoresAndComments($id) {
		//check if user is logged in and if user has the privileges to view stuff
		if ($this->_loggedInUser && in_array($id, $this->_manageableCompanies)) {
		    try {
    			$object = new \Entities\Business();
    			$object->setId($id);
    			$business = $this->_service->select($object);
    			$feedbackService = new \Services\Feedback();
    			$fb = new \Entities\Feedback();
    			$fb->setBusiness($business->getId());
    			$ratings = $feedbackService->selectMulti($fb, 'time', \Enum\Order::Desc);
    			if ($ratings) {
    				$nps = $this->_service->calculateNps($ratings);
    			} else {
    				$nps = 0;
    				//assign empty array to ratings for template. if this is null-length
    				//array, i can use foreachelse to show that nothing was found
    				$ratings = array();
    			}
    			$users = array();
    			foreach (array_keys($ratings) as $key) {
    			    $id = $ratings[$key]->getUser();
    			    if ($id != 0) {
    			        $object = new \Entities\User();
    			        $object->setId($id);
    			        $users[$ratings[$key]->getId()] = $this->_service->select($object);
    			    }
    			}
    			$this->_smarty->assign('nps', $nps);
    			$this->_smarty->assign('business', $business);
    			$this->_smarty->assign('feedbacks', $ratings);
    			$this->_smarty->assign('users', $users);
    			$this->displayStatic('commentsAndScores.tpl');
		    } catch (\Exception $e) {
		        $this->_pagePanic();
		    }
		} else {
			$this->_toLoginPage();
		}
		
	}
	
	/**
	 * Method to show comments and scores via AJAX request for comments and scores page
	 * @param array $post HTTP POST
	 * @return var Template string for html injection
	 */
	public function viewCommentSearchResults($post) {
		$fbService = new \Services\Feedback();
		$feedbacks = $fbService->commentSearch($post['detractors'], $post['passives'], $post['promoters'], $post['fromdate'], $post['todate'], $post['business']);
		if (!$feedbacks) {
			$feedbacks = array();
		} else {
			$users = array();
			foreach (array_keys($feedbacks) as $key) {
				$id = $feedbacks[$key]->getUser();
				if ($id != 0) {
					$object = new \Entities\User();
					$object->setId($id);
					$users[$feedbacks[$key]->getId()] = $this->_service->select($object);
				}
			}
		}
		$this->_smarty->assign('feedbacks', $feedbacks);
		$this->_smarty->assign('users', $users);
		return $this->_smarty->fetch('myFeedback.tpl');
	}
	
	/**
	 * Method generates analytics PNG according to input parameters.
	 * Called via AJAX
	 * @param array $post HTTP POST array
	 */
	public function viewAnalyticsSearchResults($post) {
		switch (@$post['type']) {
			case 'D':
				$pattern = 'd.m';
				$step = 'day';
				break;
			case 'W':
				$pattern = 'w';
				$step = 'week';
				break;
			case 'M':
				$pattern = 'm.Y';
				$post['start'] = '01.'.$post['start'];
				$post['end'] = '01.'.$post['end'];
				$step = 'month';
				break;
			default:
				$pattern = 'd.m';
				$step = 'day';
				break;
		}
		//get feedbacks from period and get NPS array
		$feedbacks = array();
		$score = array();
		$fbService = new \Services\Feedback();
		//read feedback for range.
		$feedbacks = $fbService->commentSearch(0, 0, 0, $post['start'], $post['end'], $post['business']);
		//determine step (day, week etc)
		$start = strtotime($post['start']);
		$end = strtotime($post['end']);
		
		for ($i = $start; $i < ($end + 1); $i = strtotime('+1 ' . $step, $i)) {
			$group = array();
			if (count($feedbacks) > 0 && $feedbacks) {
				foreach ($feedbacks as $fb) {
					//group comments by time
					if ($fb->getTime() <= strtotime('+1 ' . $step, $i)) {
						$group[] = $fb;
					}
				}
			}
			//calculate NPS
			if (count($group) > 0) {
				$score[date($pattern, $i)] = $this->_service->calculateNps($group);
			} else {
				$score[date($pattern, $i)] = 0;
			}
		}
		$object = new \Entities\Business();
		$object->setId($post['business']);
		$object = $this->_service->select($object);
		$this->generatePngChart($score, $object->getCode());
	}
	
	/**
	 * Method generates excel from comment search results. Excel is then
	 * stored into the tmp folder under business code . xlss
	 * FIXME: create a page that wants to save, do not reference directly to
	 * excel, this is a security flaw
	 * @param array $post HTTP POST array
	 */
	public function excelExport($post) {
		$fbService = new \Services\Feedback();
		$businessObj = new \Entities\Business();
		$businessObj->setId($post['business']);
		$businessObj = $this->_service->select($businessObj);
		$objPHPExcel = \Misc\Tools::initPhpExcel();
		// Set properties
		$objPHPExcel->getProperties()->setCreator($this->_loggedInUser->getGivenname());
		$objPHPExcel->getProperties()->setLastModifiedBy($this->_loggedInUser->getGivenname());
		$objPHPExcel->getProperties()->setTitle("Analytics");
		$objPHPExcel->getProperties()->setSubject("Analytics for given period");
		$objPHPExcel->getProperties()->setDescription("Output from TableTalk");
		
		switch (@$post['type']) {
			case 'D':
				break;
			case 'M':
				$post['start'] = '01.'.$post['start'];
				$post['end'] = '01.'.$post['end'];
				break;
			default:
			break;
		}
		
		// Add some data
		$objPHPExcel->setActiveSheetIndex(0);
		$feedbacks = $fbService->commentSearch(0, 0, 0, $post['start'], $post['end'], $post['business']);
		$objPHPExcel->getActiveSheet()->SetCellValue('A2', $this->_translation['periodOfAnalytics'] . $post['start'] . ' - ' . $post['end']);
		
		$objPHPExcel->getActiveSheet()->getStyle('A2')->getFont()->setSize(20);
		$objPHPExcel->getActiveSheet()->getStyle('A2')->getFont()->setBold(true);
		
		$objPHPExcel->getActiveSheet()->getRowDimension(2)->setRowHeight(30);
		
		$objPHPExcel->getActiveSheet()->SetCellValue('A4', $this->_translation['date']);
		$objPHPExcel->getActiveSheet()->SetCellValue('B4', $this->_translation['score']);
		$objPHPExcel->getActiveSheet()->SetCellValue('C4', $this->_translation['comment']);
		$objPHPExcel->getActiveSheet()->SetCellValue('D4', $this->_translation['phone']);
		$objPHPExcel->getActiveSheet()->SetCellValue('E4', $this->_translation['email']);
		$objPHPExcel->getActiveSheet()->getStyle('A4:E4')->getFont()->setBold(true);
		if (count($feedbacks) > 0 && $feedbacks) {
			foreach (array_keys($feedbacks) as $key) {
				$userObj = new \Entities\User();
				$userObj->setId($feedbacks[$key]->getUser());
				$userObj = $this->_service->select($userObj);
				if ($userObj) {
					$phone = $userObj->getPhone();
					$email = $userObj->getEmail();
				} else {
					$phone = "";
					$email = "";
				}
				$i = $key + 5;
				$objPHPExcel->getActiveSheet()->SetCellValue('A'.$i, date('d.m.Y H:i', $feedbacks[$key]->getTime()));
				$objPHPExcel->getActiveSheet()->SetCellValue('B'.$i, $feedbacks[$key]->getRating());
				$objPHPExcel->getActiveSheet()->SetCellValue('C'.$i, $feedbacks[$key]->getComment());
				$objPHPExcel->getActiveSheet()->getStyle('C'.$i)->getAlignment()->setWrapText(true);
				$objPHPExcel->getActiveSheet()->getRowDimension($i)->setRowHeight(50);
				$objPHPExcel->getActiveSheet()->SetCellValue('D'.$i, $phone);
				$objPHPExcel->getActiveSheet()->SetCellValue('E'.$i, $email);
								
			}
		}
		$objPHPExcel->getActiveSheet()->getColumnDimension('A')->setWidth(15);
		$objPHPExcel->getActiveSheet()->getColumnDimension('C')->setWidth(50);
		
		// Save Excel 2007 file
		$objWriter = \Misc\Tools::initPhpExcelWriter($objPHPExcel);
		$objWriter->save(APPPATH . 'tmp/'.$businessObj->getCode().'.xlsx');
	}
	
	/**
	 * Method shows company analytics view
	 * @param int $id Business ID for analytics
	 */
	public function viewMyAnalytics($id) {
		if ($this->_loggedInUser && in_array($id, $this->_manageableCompanies)) {
		    try {
    			$object = new \Entities\Business();
    			$object->setId($id);
    			$business = $this->_service->select($object);
    			$this->_smarty->assign('business', $business);
    	        //show last week by default
    			$this->viewAnalyticsSearchResults(array(
	                'business' => $business->getId(), 
	                'start' => date('d.m.Y', strtotime('-1 week')), 
	                'end' => date('d.m.Y')
                ));
    			//by default, generate excel report
    			$this->excelExport(array(
	                'business' => $business->getId(), 
	                'start' => date('d.m.Y', strtotime('-1 week')), 
	                'end' => date('d.m.Y')
                ));
    			$this->displayStatic('companyAnalytics.tpl');
		    } catch (\Exception $e) {
		        $this->_pagePanic();
		    }
		} else {
			$this->_toLoginPage();
		}
	}
	
	/**
	 * Method generates PNG chart from $input
	 * @param array $input array like array(xAxisVal => pointVal)
	 * @param var $businessCode Business code
	 */
	public function generatePngChart($input, $businessCode) {
		// Standard inclusions
		include(APPPATH . "lib/pChart/pData.class");
		include(APPPATH . "lib/pChart/pChart.class");
		
		// Dataset definition
		$DataSet = new \pData;
		
		foreach($input as $week => $val) {
			$DataSet->AddPoint($val, "Serie1", $week);
		}
		$DataSet->AddAllSeries();
		$DataSet->SetAbsciseLabelSerie();
		$DataSet->SetSerieName("NPS","Serie1");
		
		// Initialise the graph
		$Test = new \pChart(750,400);
		$Test->setFontProperties(APPPATH . "tmp/tahoma.ttf",8);
		$Test->setGraphArea(70,30,730,370);
		$Test->drawGraphArea(255,255,255,TRUE);
		$Test->drawScale($DataSet->GetData(),$DataSet->GetDataDescription(),20,0,0,0,TRUE,0,0);
		$Test->drawGrid(4,TRUE,230,230,230,50);
		
		// Draw the 0 line
		$Test->setFontProperties(APPPATH . "tmp/tahoma.ttf",6);
		$Test->drawTreshold(0,143,55,72,TRUE,TRUE);
		$Test->setColorPalette(0,34,139,34);  
		// Draw the line graph
		$Test->drawLineGraph($DataSet->GetData(),$DataSet->GetDataDescription());
		$Test->drawPlotGraph($DataSet->GetData(),$DataSet->GetDataDescription(),3,2,139,137,137);
		
		// Finish the graph
		$Test->setFontProperties(APPPATH . "tmp/tahoma.ttf",8);
		$Test->drawLegend(75,35,$DataSet->GetDataDescription(),255,255,255);
		$Test->setFontProperties(APPPATH . "tmp/tahoma.ttf",10);
		$Test->drawTitle(60,22,"Net Promoter Scores",50,50,50,585);
		$Test->Render(APPPATH.'tmp/'.$businessCode.'.png'); 
	}
	
	/**
	 * Method unlinks account from business
	 * @param array $post HTTP POST array
	 */
	public function endContract($id) {
		if ($this->_loggedInUser && in_array($id, $this->_manageableCompanies)) {
			// 			$id = $this->_loggedInUser->getId();
			$object = new \Entities\Business();
			$object->setId($id);
			$business = $this->_service->select($object);
			$business->setAccount('0');
			$this->_service->update($business);
		} else {
			//this does not redirect to login page since it is called via ajax
// 			$this->_toLoginPage();
		}
	}
	/**
	 * Method shows new company add/bind page
	 */
	public function viewAddForm() {
		$categoryService = new \Services\Type();
		$cat = array();
		try {
			$business = new \Entities\Business();
			$business->setAccount('0');
			$businesses = $this->_service->selectMulti($business);
			$types = $categoryService->getAllTypes();
			//translate categorys for dropdown
			foreach (array_keys($types) as $key) {
				$l = $this->_translation[$types[$key]->getName()];
				$cat[$types[$key]->getId()] = $l;
			}
			$this->_smarty->assign('cats', $cat);
			$this->_smarty->assign('availableComps', $businesses);
			$this->displayStatic('companyAdd.tpl');
		} catch (\Exception $e) {
			//notify user that something is wrong!
			$this->_pagePanic();
		}
	}
	
	/**
	 * Method tries to insert newly created business to database.
	 * @param array $post HTTP POST array
	 */
	public function insert($post) {
		try {
			if ($b = $this->_service->prepareInsert($post)) {
				$message = array('success' => $this->_translation['insertSuccess']);
				
				//insert a generic tabletalker
				$ttalker = new \Entities\TableTalker();
				$ttalker->setBusiness($b->getId());
				$ttalker->setQuestion('Kas soovitaksid meid skaalal 0-10 oma sõbrale või kolleegile? Miks?');
				$this->_service->insert($ttalker);
				
				$this->_uploadImage($_FILES, $b->getCode());
			} else {
				$message = array('error' => $this->_translation['insertFail']);
			}
		} catch (\Exception $e) {
			$message = array('error' => $this->_translation['internalError']);
		}
		$this->setMessage($message);
		$this->displayStatic('welcome.tpl');
	}
	
	/**
	 * Method creates user request to bind ones account with concrete business
	 * @param array $post HTTP POST array
	 */
	public function bind($post) {
		//create bind request for admin to oversee and confirm
		$mail = $this->_loggedInUser->getName() . '(' . $this->_loggedInUser->getGivenname() .') peab end õigustatuks saama juurdepääsu järgmistele ettevõtetele:';
		$comps = array();
		foreach ($post as $key => $e) {
			if (stristr($key, 'cId_')) {
				$parts = explode('_', $key);
				$id = $parts[1];
				$business = new \Entities\Business();
				$business->setId($id);
				$comp = $this->_service->select($business);
				$comps[] = $comp->getName();
			}
		}
		//only send message if businesses were selected
		if (count($comps) > 0) {
			$mail .= implode(',', $comps);
			\Misc\Tools::sendEmail('markuskarileet@gmail.com', 'Juurdepääsu taotlus', $mail, $mail);
		}
		$message = array('success' => $this->_translation['waitingForApproval']);//FIXME: translations!
		$this->setMessage($message);
		$this->displayStatic('welcome.tpl');
	}
}